home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / src.arc / 8250.C next >
C/C++ Source or Header  |  1989-08-19  |  9KB  |  402 lines

  1. /* OS- and machine-dependent stuff for the 8250 asynch chip on a IBM-PC
  2.  *
  3.  * 16550 support plus some statistics added mah@hpuviea.at 15/7/89
  4.  */
  5. #include <stdio.h>
  6. #include <dos.h>
  7. #include "global.h"
  8. #include "iface.h"
  9. #include "asy.h"
  10. #include "pc.h"
  11. #include "slip.h"
  12. #include "proc.h"
  13. #include "8250.h"
  14.  
  15. static int asyrxint __ARGS((unsigned dev));
  16. static void asytxint __ARGS((unsigned dev));
  17.  
  18. static struct asy Asy[ASY_MAX];
  19. unsigned Nasy;
  20. /* ASY interrupt handlers */
  21. static INTERRUPT (*Handle[])() = {asy0vec,asy1vec,asy2vec,asy3vec,asy4vec};
  22.  
  23. /* Initialize asynch port "dev" */
  24. int
  25. asy_init(dev,iface,arg1,arg2,bufsize)
  26. int16 dev;
  27. struct iface *iface;
  28. char *arg1,*arg2;    /* Attach args for address and vector */
  29. unsigned bufsize;
  30. {
  31.     register unsigned base;
  32.     register struct fifo *fp;
  33.     register struct asy *ap;
  34.     char i_state;
  35.  
  36.     ap = &Asy[dev];
  37.     ap->iface = iface;
  38.     ap->addr = htoi(arg1);
  39.     ap->vec = htoi(arg2);
  40.     /* Set up receiver FIFO */
  41.     fp = &ap->fifo;
  42.     if((fp->buf = malloc(bufsize)) == NULLCHAR){
  43.         printf("asy%d: No space for rx buffer\r\n",dev);
  44.         return -1;
  45.     }
  46.     fp->bufsize = bufsize;
  47.     fp->wp = fp->rp = fp->buf;
  48.     fp->cnt = 0;
  49.     base = ap->addr;
  50.  
  51.     /* Purge the receive data buffer */
  52.     (void)inportb(base+RBR);
  53.  
  54.     i_state = dirps();
  55.  
  56.     /* Save original interrupt vector, mask state, control bits */
  57.     ap->save.vec = getirq(ap->vec);
  58.     ap->save.mask = getmask(ap->vec);
  59.     ap->save.lcr = inportb(base+LCR);
  60.     ap->save.ier = inportb(base+IER);
  61.     ap->save.mcr = inportb(base+MCR);
  62.  
  63.     /* save speed bytes */
  64.     setbit(base+LCR,LCR_DLAB);
  65.     ap->save.divl = inportb(base+DLL);
  66.     ap->save.divh = inportb(base+DLM);
  67.     clrbit(base+LCR,LCR_DLAB);
  68.  
  69.     /* Set interrupt vector to SIO handler */
  70.     setirq(ap->vec,Handle[dev]);
  71.  
  72.     /* Set line control register: 8 bits, no parity */
  73.     outportb(base+LCR,(char)LCR_8BITS);
  74.  
  75.      /* determine if 16550, turn on FIFO mode and clear RX and TX FIFOs */
  76.      outportb(base+FCR,(char) FIFO_ENABLE);
  77.      if (inportb(base+IIR) & IIR_FIFO_ENABLED) {
  78.          ap->is_16550 = 1;
  79.          outportb(base+FCR,(char) FIFO_SETUP);
  80.      } else
  81.          ap->is_16550 = 0;
  82.  
  83.     /* Turn on receive interrupt enable in 8250, leave transmit
  84.      * and modem status interrupts turned off for now
  85.      */
  86.     outportb(base+IER,(char)IER_DAV);
  87.  
  88.     /* Set modem control register: assert DTR, RTS, turn on 8250
  89.      * master interrupt enable (connected to OUT2)
  90.      */
  91.     outportb(base+MCR,(char)(MCR_DTR|MCR_RTS|MCR_OUT2));
  92.  
  93.     /* Enable interrupt */
  94.     maskon(ap->vec);
  95.     restore(i_state);
  96.     return 0;
  97. }
  98. int
  99. asy_stop(iface)
  100. struct iface *iface;
  101. {
  102.     register unsigned base;
  103.     register struct asy *ap;
  104.     char i_state;
  105.  
  106.     ap = &Asy[iface->dev];
  107.     base = ap->addr;
  108.  
  109.     /* Purge the receive data buffer */
  110.     (void)inportb(base+RBR);
  111.  
  112.      /* and hardware fifos if available */
  113.      if (ap->is_16550)
  114.          outportb(base+FCR,(char) FIFO_SETUP);
  115.  
  116.     /* Restore original interrupt vector and 8259 mask state */
  117.     i_state = dirps();
  118.     setirq(ap->vec,ap->save.vec);
  119.     if(ap->save.mask)
  120.         maskon(ap->vec);
  121.     else
  122.         maskoff(ap->vec);
  123.  
  124.     /* Restore speed regs */
  125.     setbit(base+LCR,LCR_DLAB);
  126.     outportb(base+DLL,ap->save.divl);    /* Low byte */
  127.     outportb(base+DLM,ap->save.divh);    /* Hi byte */
  128.     clrbit(base+LCR,LCR_DLAB);
  129.  
  130.     /* Restore control regs */
  131.     outportb(base+LCR,ap->save.lcr);
  132.     outportb(base+IER,ap->save.ier);
  133.     outportb(base+MCR,ap->save.mcr);
  134.     restore(i_state);
  135.     return 0;
  136. }
  137. /* Asynchronous line I/O control */
  138. int
  139. asy_ioctl(iface,argc,argv)
  140. struct iface *iface;
  141. int argc;
  142. char *argv[];
  143. {
  144.     if(argc < 1){
  145.         printf("%d\r\n",Asy[iface->dev].speed);
  146.         return 0;
  147.     }
  148.     return asy_speed(iface->dev,atoi(argv[0]));
  149. }
  150. /* Set asynch line speed */
  151. int
  152. asy_speed(dev,speed)
  153. int16 dev;
  154. int speed;
  155. {
  156.     register unsigned base;
  157.     register int divisor;
  158.     char i_state;
  159.  
  160.     if(speed == 0 || dev >= Nasy)
  161.         return -1;
  162.  
  163.     base = Asy[dev].addr;
  164.     Asy[dev].speed = speed;
  165.  
  166.     divisor = BAUDCLK / (long)speed;
  167.  
  168.     i_state = dirps();
  169.  
  170.     /* Purge the receive data buffer */
  171.     (void)inportb(base+RBR);
  172.      if (Asy[dev].is_16550)       /* clear tx+rx fifos */
  173.          outportb(base+FCR,(char) FIFO_SETUP);
  174.  
  175.     /* Turn on divisor latch access bit */
  176.     setbit(base+LCR,LCR_DLAB);
  177.  
  178.     /* Load the two bytes of the register */
  179.     outportb(base+DLL,(char)(divisor & 0xff));        /* Low byte */
  180.     outportb(base+DLM,(char)((divisor >> 8) & 0xff));    /* Hi byte */
  181.  
  182.     /* Turn off divisor latch access bit */
  183.     clrbit(base+LCR,LCR_DLAB);
  184.  
  185.     restore(i_state);
  186.     return 0;
  187. }
  188.  
  189. /* Send a buffer to serial transmitter */
  190. void
  191. asy_output(dev,buf,cnt)
  192. unsigned dev;
  193. char *buf;
  194. unsigned short cnt;
  195. {
  196.     register struct dma *dp;
  197.     unsigned base;
  198.     char i_state;
  199.  
  200.     if(dev >= Nasy)
  201.         return;
  202.     base = Asy[dev].addr;
  203.     dp = &Asy[dev].dma;
  204.     i_state = dirps();
  205.     if(dp->flags){
  206.         restore(i_state);
  207.         return;    /* Already busy */
  208.     }
  209.     dp->data = buf;
  210.     dp->cnt = cnt;
  211.     dp->flags = 1;
  212.  
  213.     /* Enable transmitter buffer empty interrupt and simulate
  214.      * an interrupt; this will get things rolling.
  215.      */
  216.     setbit(base+IER,IER_TxE);
  217.     asytxint(dev);
  218.     restore(i_state);
  219. }
  220. /* Blocking read from asynch line
  221.  * Returns count of characters read
  222.  */
  223. char
  224. get_asy(dev)
  225. int16 dev;
  226. {
  227.     char i_state;
  228.     register struct fifo *fp;
  229.     char c;
  230.  
  231.     fp = &Asy[dev].fifo;
  232.  
  233.     i_state = dirps();
  234.     while(fp->cnt == 0)
  235.         pwait(fp);
  236.     fp->cnt--;
  237.     restore(i_state);
  238.  
  239.     c = *fp->rp++;
  240.     if(fp->rp >= &fp->buf[fp->bufsize])
  241.         fp->rp = fp->buf;
  242.  
  243.     return c;
  244. }
  245. /* Interrupt handler for 8250 asynch chip */
  246. void
  247. asyint(dev)
  248. unsigned dev;
  249. {
  250.     register unsigned base;
  251.     register char iir;
  252.     struct fifo *fp;
  253.     int cnt = 0;
  254.  
  255.     base = Asy[dev].addr;
  256.     fp = &Asy[dev].fifo;
  257.     while(((iir = inportb(base+IIR)) & IIR_IP) == 0){
  258.         switch(iir & IIR_ID){
  259.         case IIR_RDA:    /* Receiver interrupt */
  260.             cnt += asyrxint(dev);
  261.             break;
  262.         case IIR_THRE:    /* Transmit interrupt */
  263.             asytxint(dev);
  264.             break;
  265.         }
  266.          /* should happen at end of a single slip packet */
  267.          if (iir & IIR_FIFO_TIMEOUT)
  268.              Asy[dev].fifotimeouts++;
  269.     }
  270.     if(cnt != 0)
  271.         psignal(fp,1);
  272. }
  273.  
  274. /* Process 8250 receiver interrupts */
  275. static int
  276. asyrxint(dev)
  277. unsigned dev;
  278. {
  279.     unsigned base;
  280.     register struct fifo *fp;
  281.     struct asy *asyp;
  282.     char c;
  283.     int cnt = 0;
  284.     char lsr;
  285.  
  286.     asyp = &Asy[dev];
  287.     base = asyp->addr;
  288.     fp = &asyp->fifo;
  289.     for(;;){
  290.         lsr = inportb(base+LSR);
  291.         if(lsr & LSR_OE)
  292.             asyp->overrun++;
  293.  
  294.         if(lsr & LSR_DR){
  295.             asyp->rxchar++;
  296.             c = inportb(base+RBR);
  297.             /* If buffer is full, we have no choice but
  298.              * to drop the character
  299.              */
  300.             if(fp->cnt != fp->bufsize){
  301.                 *fp->wp++ = c;
  302.                 if(fp->wp >= &fp->buf[fp->bufsize])
  303.                     /* Wrap around */
  304.                     fp->wp = fp->buf;
  305.                 fp->cnt++;
  306.                 cnt++;
  307.              } else
  308.                 asyp->rxdropped++;
  309.         } else
  310.             break;
  311.     }
  312.      asyp->rxints++;
  313.     return cnt;
  314. }
  315. /* Handle 8250 transmitter interrupts */
  316. static void
  317. asytxint(dev)
  318. unsigned dev;
  319. {
  320.     register struct dma *dp;
  321.     register unsigned base;
  322.      register int count;
  323.     struct asy *asyp;
  324.  
  325.     asyp = &Asy[dev];
  326.     base = asyp->addr;
  327.     dp = &asyp->dma;
  328.     if(!dp->flags){
  329.         /* "Shouldn't happen", but disable transmit
  330.          * interrupts anyway
  331.          */
  332.         clrbit(base+IER,IER_TxE);
  333.         return;    /* Nothing to send */
  334.     }
  335.  
  336.      /* if it's a 16550, load up to 16 chars into the tx hw fifo 
  337.          * at once. With an 8250, it can be on char at most.
  338.      */
  339.  
  340.      if (asyp->is_16550) {
  341.         count = min(dp->cnt,OUTPUT_FIFO_SIZE);
  342.  
  343.              /* 16550: LSR_THRE will drop after the first char loaded
  344.                  * so we can't look at this bit to determine if the hw fifo is
  345.               * full. There seems to be no way to determine if the tx fifo
  346.               * is full (any clues?). So we should never get here while the
  347.           * fifo isn't empty yet.
  348.                  */
  349.          asyp->txchar += count;
  350.          dp->cnt -= count;
  351.  
  352.                   while(count--)
  353.                  outportb(base+THR,*dp->data++);
  354.  
  355.              if(dp->cnt == 0){
  356.                  dp->flags = 0;
  357.                  /* Disable transmit interrupts */
  358.                  clrbit(base+IER,IER_TxE);
  359.                  asytxdone(dev);
  360.              }
  361.      } else {    /* 8250 */
  362.              while(inportb(base+LSR) & LSR_THRE){
  363.                  asyp->txchar++;
  364.                  outportb(base+THR,*dp->data++);
  365.  
  366.                  if(--dp->cnt == 0){
  367.                     dp->flags = 0;
  368.                    /* Disable transmit interrupts */
  369.                     clrbit(base+IER,IER_TxE);
  370.                     asytxdone(dev);
  371.                     break;
  372.                  }
  373.         }
  374.     }
  375. }
  376. int
  377. stxrdy(dev)
  378. int16 dev;
  379. {
  380.     return(!Asy[dev].dma.flags);
  381. }
  382. int
  383. doasystat(argc,argv,p)
  384. int argc;
  385. char *argv[];
  386. void *p;
  387. {
  388.     register struct asy *asyp;
  389.  
  390.     for(asyp = Asy;asyp < &Asy[Nasy];asyp++){
  391.         printf("%s: %s",asyp->iface->name,
  392.          asyp->is_16550 ? "NS16550A" : "");
  393.         printf(" RX: int %lu chr %lu ovrn %lu",
  394.          asyp->rxints,asyp->rxchar,asyp->overrun);
  395.         if(asyp->is_16550)
  396.             printf(" fifotim %lu",asyp->fifotimeouts);
  397.         printf(" TX: int %lu chr %lu\n",asyp->txints,asyp->txchar);
  398.     }
  399.     return 0;
  400. }
  401.  
  402.